#pragma once
#include<stdio.h>
#include <sys/time.h>
#include <stdexcept>
#include "Player.h"

class Game {
public:

	class IOnGameListener {
	public:
		virtual void onStart(Board* board) = 0;
		virtual void onComplete(Board* board) = 0;
		virtual bool onChangeTurn(Board* board, Player* player) = 0;
		virtual void onPutStone(Player* player, Board* board, Cell* cell) = 0;
		virtual void onGiveUp(Player* player) = 0;
	};

	class PrintListener: public IOnGameListener {
		struct timeval mTime;
		struct timeval mStart;

		void onStart(Board* board) {
			gettimeofday(&mTime, NULL);
			gettimeofday(&mStart, NULL);
			cout << "start" << endl;
			cout << board->toString() << endl;
		}

		bool onChangeTurn(Board* board, Player* player) {
			return true;
		}

		void onComplete(Board* board) {
			struct timeval now;
			gettimeofday(&now, NULL);
			int time = (now.tv_sec * 1000 + now.tv_usec / 1000) - (mStart.tv_sec * 1000 + mStart.tv_usec / 1000);
			cout << "complete" << endl;
			cout << board->toString() << endl;
			cout << "time : " << time << endl;
		}

		void onPutStone(Player* player, Board* board, Cell* cell) {
			struct timeval now;
			gettimeofday(&now, NULL);
			int time = (now.tv_sec * 1000 + now.tv_usec / 1000) - (mTime.tv_sec * 1000 + mTime.tv_usec / 1000);

			cout << player->toString() << " : " << (cell == NULL ? "passed" : cell->toStringData()) << " Mind: " << player->hearMind() << " : " << time << endl;
			if (cell != NULL) {
				cout << board->toString() << endl;
			}
			mTime = now;
		}

		void onGiveUp(Player* player) {
			cout << player->toString() << " give up." << endl;
		}
	};

	class GameException: public std::domain_error {
	private:
		Player* mPlayer;
	public:
		GameException(Player* player) :
				std::domain_error("give up") {
			mPlayer = player;
		}
		Player* getPlayer() {
			return mPlayer;
		}
	};

private:
	Player** mPlayers;
	IOnGameListener* mListener;
	bool mPrePass;
protected:
	Board* mBoard;

public:
	Game(Player* player1, Player* player2, Board* board = 0);
	~Game();
	void setListener(IOnGameListener* listener);
	void start();
	void play();
	void start2();
	void play2();
//    void playNext2(final Player player);
	bool playNext(Player* player);
	int getTurnCount();
	Board::State* getState();
	void onGameStart();
	void onGameComplete();
	void onGamePutStone(Player player, Cell cell);
	void onGameGiveUp(Player player);
private:
	void init();
	bool isOver();
};

